package reports.servlets;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.util.PDFImageWriter;

import com.crystaldecisions.report.web.viewer.CrPrintMode;
import com.crystaldecisions.report.web.viewer.CrystalReportViewer;
import com.crystaldecisions.sdk.occa.report.application.DBOptions;
import com.crystaldecisions.sdk.occa.report.application.DatabaseController;
import com.crystaldecisions.sdk.occa.report.application.ParameterFieldController;
import com.crystaldecisions.sdk.occa.report.application.ReportClientDocument;
import com.crystaldecisions.sdk.occa.report.data.ConnectionInfos;
import com.crystaldecisions.sdk.occa.report.data.Fields;
import com.crystaldecisions.sdk.occa.report.data.IConnectionInfo;
import com.crystaldecisions.sdk.occa.report.data.ParameterField;
import com.crystaldecisions.sdk.occa.report.data.ParameterFieldDiscreteValue;
import com.crystaldecisions.sdk.occa.report.data.Values;
import com.crystaldecisions.sdk.occa.report.exportoptions.IExportOptions;
import com.crystaldecisions.sdk.occa.report.exportoptions.ReportExportFormat;
import com.crystaldecisions.sdk.occa.report.lib.PropertyBag;
import com.crystaldecisions.sdk.occa.report.lib.ReportSDKParameterFieldException;


public class ReporteServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    private static final String URL_RELATIVA = "/WEB-INF/reportes/";
    
    private final String CONNECTION_STRING = "!com.microsoft.sqlserver.jdbc.SQLServerDriver!jdbc:sqlserver://10.10.149.195:1433!user={userid}!password={password}";
    private final String TRUSTEDCON = "false";
    private final String PREQESERVERNAME = "jdbc:sqlserver://10.10.149.195:1433";
    private final String SERVERTYPE = "JDBC (JNDI)";
    private final String DBCLASSNAME = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
    private final String USEJDBC = "true";
    private final String SERVERNAME = "jdbc:sqlserver://10.10.149.195:1433"; 
    private final String CONNECTIONURL = "jdbc:sqlserver://10.10.149.195:1433";
    private final String SERVER = "10.10.149.195";
    private final String DATABASE_DLL = "crdb_jdbc.dll";

    
    private String folderReportes;

	//private boolean add;
	
	public ReporteServlet() {
        super();        
    }
	
	
	public String getFolderReportes() {
		return folderReportes;
	}

	public void setFolderReportes(String folderReportes) {
		this.folderReportes = folderReportes;
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		if(generarAtributosReporte(request, "formato") == null){
			
			procesarPeticion(request,response);
			
		}else{
			
			procesarStreamPeticion(request, response, request.getParameter("formato"));
			
		}
	}
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		if(request.getParameter("formato") == null){
			
			procesarPeticion(request,response);
			
		}else{			
			
			procesarStreamPeticion(request, response, request.getParameter("formato"));
			
		}	
	}
	
	
	
	protected void procesarStreamPeticion(HttpServletRequest request, HttpServletResponse response, String formato) throws ServletException, IOException {
		
		String contentType = null;
		String fileName = null;
		ReportExportFormat reportExportFormat = null;
				
		if(generarAtributosReporte(request, "formato").equals("pdf")){			
			contentType = "application/pdf";
			fileName = "reporte.pdf";
			reportExportFormat = ReportExportFormat.PDF;
		}else{			
			if(generarAtributosReporte(request, "formato").equals("doc")){
				contentType = "application/msword";
				fileName = "reporte.doc";
				reportExportFormat = ReportExportFormat.MSWord;
			}else{				
				if(generarAtributosReporte(request, "formato").equals("xls") ){
					contentType = "application/vnd.ms-excel";
					fileName = "reporte.xls";
					reportExportFormat = ReportExportFormat.MSExcel;
				}else{					
					if(generarAtributosReporte(request, "formato").equals("img") ){
						contentType = "image/jpeg";
						fileName = "reporte.img";
						reportExportFormat = ReportExportFormat.PDF;
					}else{					
						response.sendError(501,"Formato de reporte invalido");
						return;
					}					
				}
			}
		}
					
		try{
			//Se realiza la apertura del reporte para poder acceder a sus propiedades		
			
			StringBuilder sbUrl = new StringBuilder(URL_RELATIVA);
			
			if( generarAtributosReporte(request, "folder") != null){
				
				sbUrl.append(generarAtributosReporte(request, "folder")).append("/");
				
			}
			
			sbUrl.append(generarAtributosReporte(request, "nombre"));
			
			
			System.out.println("URL reporte = " + sbUrl);
			
			
			ReportClientDocument reportClientDocument = new ReportClientDocument();
			
			reportClientDocument.setLocale(new Locale("es","MX"));			
			
			reportClientDocument.open(sbUrl.toString(), 0);
			
			List<ParametroReporte> listaParametros = generarParametros(request);
			
			Iterator<ParametroReporte> iParametros = listaParametros.iterator();
			
			ParameterFieldController paramController = reportClientDocument.getDataDefController().getParameterFieldController();			
			
			while(iParametros.hasNext()){
			
				ParametroReporte parametroReporte = iParametros.next();
		
				paramController.setCurrentValue("", parametroReporte.getParametro(), parametroReporte.getValor());
			}	
				
			Properties prop = new Properties();
			InputStream in = ReporteServlet.class.getResourceAsStream("/config/reportconfig.properties");
			prop.load(in);
			in.close();			
			
			paramController.setCurrentValue("", "database", prop.getProperty("report.source.default"));
			
			//Se coloca el nombre de usuario y password al datasource del reporte
			
			
			DatabaseController databaseController = reportClientDocument.getDatabaseController();
			
			
			databaseController.logon("sa", "F3C47rywsh3r3i");
			
			response.setCharacterEncoding("UTF-8"); 
			
			//response.setHeader("Content-disposition", "inline;filename=reporte.pdf");
			//response.setContentType("application/pdf");			
			//InputStream byteArrayInputStream = reportClientDocument.getPrintOutputController().export(ReportExportFormat.PDF);
			
			response.setHeader("Content-disposition", "inline;filename=" + fileName);
			response.setContentType(contentType);			
			InputStream inputStream = reportClientDocument.getPrintOutputController().export(reportExportFormat);		
			
			
			
			if(contentType.equals("image/jpeg")){
				
				PDDocument pdDocument = PDDocument.load(inputStream);
				
				PDPage pdPage = (PDPage) pdDocument.getDocumentCatalog().getAllPages().get(0);
				BufferedImage originalImage = pdPage.convertToImage(BufferedImage.TYPE_3BYTE_BGR,350);
			    
				
				
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				ImageIO.write( originalImage, "jpg", baos );
				baos.flush();				
				byte[] imageInByte = baos.toByteArray();
				
				baos.close();
				pdDocument.close();
			
				response.getOutputStream().write(imageInByte);
			
			}else{
			
				byte[] buffer = new byte[inputStream.available()];
				int bytesRead = 0;
				
				while((bytesRead = inputStream.read(buffer)) != -1) {
					response.getOutputStream().write(buffer, 0, bytesRead);	
				}
				
			}
			
			
			
			
			
			
			
			
			
			
			//response.getOutputStream().flush();
			//response.getOutputStream().close();		
			
			//Se cierra el acceso a las propiedades del reporte
			reportClientDocument.close();
			
		}catch(ReportSDKParameterFieldException rfe){
			rfe.printStackTrace();
			System.out.println(rfe.getMessage());
			response.sendError(501, rfe.getMessage());
		}
		catch(Exception e){
			e.printStackTrace();
			System.out.println(e.getMessage());
			response.sendError(500, e.getMessage());
		}

		
	}
	
	

	protected void procesarPeticion(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		ParameterField pf = null;
		ParameterFieldDiscreteValue pdv = null;
		Values v = null;
		
		try{
			//Se realiza la apertura del reporte para poder acceder a sus propiedades
			
			
			StringBuilder sbUrl = new StringBuilder(URL_RELATIVA);
			
			if( generarAtributosReporte(request, "folder") != null){
				
				sbUrl.append(generarAtributosReporte(request, "folder")).append("/");
				
			}
			
			sbUrl.append(generarAtributosReporte(request, "nombre"));
			
			
			System.out.println("URL reporte = " + sbUrl);
			
			//generarParametros(request);
			
			ReportClientDocument reportClientDocument = new ReportClientDocument();
			
			reportClientDocument.open(sbUrl.toString(), 0);
			
			List<ParametroReporte> listaParametros = generarParametros(request);
			
			Iterator<ParametroReporte> iParametros = listaParametros.iterator();
			
			Fields f = new Fields();
			
			while(iParametros.hasNext()){
			
				ParametroReporte pr = iParametros.next();
				
				pf = new ParameterField();
				pf.setName(pr.getParametro());
				
				pdv = new ParameterFieldDiscreteValue();
				pdv.setValue(pr.getValor());
				
				v = new Values();
				v.add(pdv);
				pf.setCurrentValues(v);
				f.add(pf);	
				
			}	
			
			Properties prop = new Properties();
			InputStream in = ReporteServlet.class.getResourceAsStream("/config/reportconfig.properties");
			prop.load(in);
			in.close();
			
			pf = new ParameterField();
			pf.setName("database");
			
			pdv = new ParameterFieldDiscreteValue();
			pdv.setValue(prop.getProperty("report.source.default"));
			
			v = new Values();
			v.add(pdv);
			
			pf.setCurrentValues(v);
			f.add(pf);
			
			
			//Se coloca el nombre de usuario y password al datasource del reporte
			
			ConnectionInfos connInfos = new ConnectionInfos();
			DatabaseController dataBaseController = reportClientDocument.getDatabaseController();
			
			IConnectionInfo connInfo1 = dataBaseController.getConnectionInfos(null).getConnectionInfo(0);
			connInfo1.setUserName("sa");
			connInfo1.setPassword("F3C47rywsh3r3i");
			
			PropertyBag atributos = connInfo1.getAttributes();
			atributos.clear();
			
			connInfos.add(connInfo1);
			
			//Se crea un PropertyBag para los parametros de la nueva conexion
		 	PropertyBag propiedades = new PropertyBag();
				
			//Se establecen los parametros de conexion
		 	propiedades.put("JDBC Connection String", CONNECTION_STRING);
		 	propiedades.put("Trusted_Connection", TRUSTEDCON);
		 	propiedades.put("PreQEServerName", PREQESERVERNAME);
		 	propiedades.put("Server Type", SERVERTYPE);
		 	propiedades.put("Database DLL", DATABASE_DLL);
		 	propiedades.put("Database Class Name", DBCLASSNAME);
		 	propiedades.put("Use JDBC", USEJDBC);
		 	propiedades.put("Database Name", prop.getProperty("report.source.default"));
			propiedades.put("Server Name", SERVERNAME);
			propiedades.put("Connection URL", CONNECTIONURL);
			propiedades.put("Server", SERVER);
			propiedades.put("Database", prop.getProperty("report.source.default"));
			
			connInfo1.setAttributes(propiedades);
			
			int replaceParams = DBOptions._ignoreCurrentTableQualifiers + DBOptions._doNotVerifyDB;

			//Se reemplaza la conexion actual con la nueva.Parametros Conexion Anterior, Conexion Nueva, etc.
			dataBaseController.replaceConnection(dataBaseController.getConnectionInfos(null).getConnectionInfo(0), connInfo1 , f, replaceParams);
			
			//Se crea el visualizador del reporte
			CrystalReportViewer viewer = new CrystalReportViewer();
		
			//Se agregan el reporte con sus parametros y se configuran las propiedades del visualizador
			viewer.setParameterFields(f);
			viewer.setReportSource(reportClientDocument.getReportSource());	
			viewer.setDisplayPage(true);
			viewer.setDisplayToolbar(true);
			viewer.setDatabaseLogonInfos(connInfos);
			viewer.setEnableLogonPrompt(false);
			viewer.setEnableParameterPrompt(false);
			viewer.setPrintMode(CrPrintMode.ACTIVEX);
			viewer.setHasToggleGroupTreeButton(false);
			viewer.setHasDrilldownTabs(false);
			viewer.setHasToggleParameterPanelButton(false);
			viewer.setToolPanelWidth(0);
			
			
			
			//Se cierra el acceso a las propiedades del reporte
			reportClientDocument.close();
			
			//Se para el visualizador como atributo del contexto para posteriormente delegar la solicitud
			//al reporteOK.jsp encargado de desplegar el reporte
			getServletContext().setAttribute("reporte", viewer);
			request.getRequestDispatcher("reporte.jsp").forward(request, response);
		}catch(Exception e){
			e.printStackTrace();
			System.out.println(e.getMessage());
		}

		
	}

	private List<ParametroReporte> generarParametros(HttpServletRequest request){
		
		Enumeration<String> nombresParam = request.getParameterNames();
		//Fields f = new Fields();
		List<ParametroReporte> parametrosLista  = new ArrayList<ParametroReporte>();
		
		while(nombresParam.hasMoreElements()){
			
			String parametro = nombresParam.nextElement();
		
			if(parametro.split("_")[0].equals("prm")){
			
				ParametroReporte pr = new ParametroReporte();
				
				pr.setParametro( parametro.split("_")[1] );
				pr.setValor( request.getParameter(parametro) );
				parametrosLista.add(pr);
				
				
			}
		}	
		
		System.out.println("Parametros del reporte \n\n");
		
		Iterator<ParametroReporte> iparametros = parametrosLista.iterator();
		
		while(iparametros.hasNext()){
			
			ParametroReporte pr = iparametros.next();
			System.out.println("paremetro = "	+ pr.getParametro() );
			System.out.println("valor = "	+ pr.getValor() );
			
		}
		
		System.out.println(" ----- --- --- - - - -- -----");
		
		return parametrosLista;
	}

	private String generarAtributosReporte(HttpServletRequest request, String atributo){
		
		Enumeration<String> nombresParam = request.getParameterNames();
		String atributo_ = null;
		
				
		while(nombresParam.hasMoreElements()){
			
			String parametro = nombresParam.nextElement();
				
			if(parametro.split("_")[0].equals("rpt")){
				
				String nombreParam = parametro.split("_")[1];
				
				if(nombreParam.equals(atributo)){
					
					atributo_ = request.getParameter(parametro);
		
				}		
			
			}
		
		}	
		
		return atributo_;	
	}

	private class ParametroReporte{
		
		private String parametro;
		
		private String valor;
		
		public String getParametro() {
			return parametro;
		}
		
		public void setParametro(String parametro) {
			this.parametro = parametro;
		}
		
		public String getValor() {
			return valor;
		}
		
		public void setValor(String valor) {
			this.valor = valor;
		}
		
		
	}
}
